/*
 * Copyright 2025 arisgo@163.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.arisgo.cloud.auth.sys.service.impl;

import com.arisgo.cloud.auth.sys.entity.Tenant;
import com.arisgo.cloud.auth.sys.entity.TenantFunction;
import com.arisgo.cloud.auth.sys.entity.TenantUser;
import com.arisgo.cloud.auth.sys.entity.User;
import com.arisgo.cloud.auth.sys.mapper.FunctionMapper;
import com.arisgo.cloud.auth.sys.mapper.TenantFunctionMapper;
import com.arisgo.cloud.auth.sys.mapper.TenantMapper;
import com.arisgo.cloud.auth.sys.mapper.TenantUserMapper;
import com.arisgo.cloud.auth.sys.mapper.UserMapper;
import com.arisgo.cloud.auth.sys.service.TenantService;
import com.arisgo.cloud.auth.sys.vo.TenantVo;
import com.arisgo.cloud.auth.sys.vo.UserVo;
import com.arisgo.cloud.common.utils.AssertUtil;
import com.arisgo.cloud.core.Constant;
import com.arisgo.cloud.core.redis.UserInfo;
import com.arisgo.cloud.core.token.TokenGenerator;
import com.arisgo.cloud.web.mybatis.service.CloudServiceImpl;
import com.arisgo.cloud.web.param.Param;
import com.arisgo.cloud.web.param.Search;
import com.arisgo.cloud.web.utils.RequestUtil;
import com.google.common.collect.Lists;
import com.mybatisflex.core.query.QueryWrapper;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.util.List;
import java.util.Map;

/**
 * 租户
 *
 * @author Arisgo
 * @since 2024-06-14
 */
@Service
@AllArgsConstructor
public class TenantServiceImpl extends CloudServiceImpl<TenantMapper, Tenant, TenantVo> implements TenantService {

    private static final Logger log = LoggerFactory.getLogger(TenantServiceImpl.class);
    private final TenantUserMapper tenantUserMapper;
    private final FunctionMapper functionMapper;
    private final UserMapper userMapper;
    private final TokenGenerator tokenGenerator;
    protected final RedisTemplate<String, Object> redisTemplate;
    private final TenantFunctionMapper tenantFunctionMapper;

    @Override
    public Tenant getInstanceModel() {
        return new Tenant();
    }

    @Override
    public TenantVo getInstanceVo() {
        return new TenantVo();
    }

    @Override
    public Map<Object, Object> create(TenantVo vo) {
        // 校验数据
        AssertUtil.notNull(vo, "参数为空！");
        AssertUtil.notNull(vo.getName(), "租户名为空！");
        // 创建租户，新租户默认3年有效期
        LocalDate now = LocalDate.now();
        if (vo.getStartDate() == null) {
            vo.setStartDate(now);
        }
        if (vo.getEndDate() == null) {
            vo.setEndDate(now.plusYears(3));
        }
        Long userId = RequestUtil.getUserId();
        vo.setUserId(userId);
        vo.setStatus(0);
        TenantVo tenant = this.save(vo);
        // 关联租户
        TenantUser tenantUser = new TenantUser();
        tenantUser.setTenantId(tenant.getId());
        tenantUser.setUserId(userId);
        tenantUser.setStatus(0);
        tenantUserMapper.insert(tenantUser);
        // 租户开通默认功能包
        List<Long> functionIds = functionMapper.findDefaultFunction();
        if (!CollectionUtils.isEmpty(functionIds)) {
            List<TenantFunction> tenantFunctions = Lists.newArrayListWithCapacity(functionIds.size());
            for (Long functionId : functionIds) {
                TenantFunction tenantFunction = new TenantFunction();
                tenantFunction.setTenantId(tenant.getId());
                tenantFunction.setFunctionId(functionId);
                tenantFunction.setStartDate(tenant.getStartDate());
                tenantFunction.setEndDate(tenant.getEndDate());
                tenantFunctions.add(tenantFunction);
            }
            tenantFunctionMapper.insertBatch(tenantFunctions);
        }
        // 变更用户默认租户
        User user = userMapper.selectOneById(userId);
        user.setTenantId(tenant.getId());
        userMapper.update(user);
        // TODO 2025-03-16 新增员工信息
        // TODO 2025-03-16 记录日志

        // 刷新token，刷新redis
        UserInfo userInfo = RequestUtil.getUser();
        userInfo.setTenantId(tenant.getId());
        userInfo.setTenantName(tenant.getName());
        userInfo.setOwner(true);
        userInfo.setStaffId(null);

        return tokenGenerator.generator(userInfo);
    }

    @Override
    public Map<Object, Object> toggle(Long tenantId) {
        // 获取目标租户，并验证租户是否可用
        UserInfo userInfo = RequestUtil.getUser();
        AssertUtil.isTrue(checkTenantAccount(tenantId, userInfo.getUserId()), "租户账号不可用！");

        // TODO 2025-03-16 记录切换日志
        // 更新默认租户
        UserVo user = userMapper.findUserByAccount(userInfo.getUsername());
        User update = new User();
        update.setId(user.getId());
        update.setTenantId(tenantId);
        userMapper.update(update);

        // 更新登陆信息，刷新token，刷新redis
        Tenant tenant = this.mapper.selectOneById(tenantId);
        userInfo.setTenantId(tenantId);
        userInfo.setTenantName(tenant.getName());
        userInfo.setOwner(tenant.getUserId().equals(userInfo.getUserId()));
        userInfo.setStaffId(user.getStaffId());
        return tokenGenerator.generator(userInfo);
    }

    @Override
    public boolean checkTenantAccount(Long tenantId, Long userId) {
        // 校验租户是否可用
        TenantVo tenant = this.mapper.findTenantById(tenantId);
        if (null == tenant) {
            log.warn("租户校验 => 无有效租户！tenantId: {}", tenantId);
            return false;
        } else if (tenant.getStatus().equals(1)) {
            log.warn("租户校验 => 租户处于锁定状态！tenantId: {}", tenantId);
            // TODO 2025-03-16 获取当前时间是否已解锁
            // 未解锁：返回false
            // 已解锁：更新状态为正常，继续校验
            return false;
        } else if (tenant.getStatus().equals(-1)) {
            log.info("租户校验 => 租户未激活！tenantId: {}", tenantId);
            if (!tenant.getUserId().equals(userId)) {
                return false;
            }
            log.info("租户校验 => 租户所有人首次登陆，默认激活。userId: {}, tenantId: {}", userId, tenantId);
            tenant.setStatus(0);
            this.update(tenant);
        }

        // 校验用户是否可用
        QueryWrapper wrapper = new QueryWrapper();
        Search.creator(Param.creator(TenantUser.TENANT_ID, tenantId), Param.creator(TenantUser.USER_ID, userId))
                .buildWrapper(wrapper);
        TenantUser tenantUser = tenantUserMapper.selectOneByQuery(wrapper);
        if (null == tenantUser) {
            log.warn("租户账号校验 => 账号未绑定！tenantId: {}", tenantId);
            return false;
        } else if (tenantUser.getStatus().equals(1)) {
            log.warn("租户账号校验 => 账号已冻结！tenantId: {}", tenantId);
            // TODO 2025-03-16 获取当前时间是否已解冻
            // 未解冻：返回false
            // 已解冻：更差账号状态
            return false;
        } else if (tenantUser.getStatus().equals(-1)) {
            log.info("租户账号校验 => 激活当前账号。tenantId: {}, userId: {}", tenantId, userId);
            tenantUser.setStatus(0);
            tenantUserMapper.update(tenantUser);
        }
        return true;
    }

    @Override
    public Boolean logout(Long tenantId) {
        this.mapper.logout(tenantId);
        // 注销登陆
        redisTemplate.delete(Constant.TOKEN_PREFIX + String.valueOf(RequestUtil.getUserId()));
        return true;
    }

    @Override
    public Map<Object, Object> changeManager(Long tenantId, Long userId) {
        Tenant tenant = this.mapper.selectOneById(tenantId);
        tenant.setUserId(userId);
        this.mapper.update(tenant);
        return toggle(tenantId);
    }
}
